package utils

import (
	"errors"
	"fmt"
	"strings"
)

type Queue struct {
	Data   []int
	Size   int
	Top    int
	Bottom int
	Empty  bool
}

func GetQueue(size int) *Queue {
	queue := new(Queue)
	queue.Size = size
	queue.Data = make([]int, size, size)
	queue.Empty = true
	queue.Top = 0
	queue.Bottom = 0
	return queue
}

func (q *Queue) OutQueue() (err error, data int) {
	if q.Empty {
		return errors.New("Empty Queue"), 0
	}
	data = q.Data[q.Bottom]
	q.Bottom++
	if q.Bottom >= q.Size {
		q.Bottom = 0
	}
	if q.Bottom == q.Top {
		q.Empty = true
	}
	return nil, data
}

func (q *Queue) InQueue(data int) (needOut bool, num int) {
	if q.Top != q.Bottom {

		q.Data[q.Top] = data
		q.Top++
		if q.Top >= q.Size {
			q.Top = 0
		}

		return false, 0
	} else {
		if q.Empty {

			q.Data[q.Top] = data
			q.Top++
			if q.Top >= q.Size {
				q.Top = 0
			}
			q.Empty = false
			return false, 0

		} else {
			_, num = q.OutQueue()
			q.Empty = false
			q.InQueue(data)
			return true, num
		}
	}
}

func (q *Queue) ToString() string {
	var s strings.Builder
	for i := 0; i < q.Size; i++ {
		fmt.Println(q.Data[i])
	}
	if q.Top > q.Bottom {
		for i := q.Bottom; i < q.Top; i++ {
			s.WriteString(string(i))
			s.WriteString(" , ")
		}
	} else {
		for i := q.Bottom; i < q.Size; i++ {
			s.WriteString(string(i))
			s.WriteString(" , ")
		}
		for i := 0; i < q.Top; i++ {
			s.WriteString(string(i))
			s.WriteString(" , ")
		}
	}
	return s.String()
}
